<!DOCTYPE html>
<html lang=zh-CN>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="google-site-verification" content="xBT4GhYoi5qRD5tr338pgPM5OWHHIDR6mNg1a3euekI" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta property="og:description" content="samuel-24276的博客">
    <meta property="og:type" content="website">
    <meta name="description" content="samuel-24276的博客">
    <meta name="keyword"  content="aircloud">
    <link rel="shortcut icon" href="/myblog/img/favicon.ico">

    <title>
        
        TCP/UDP协议与socket编程 - samuel-24276的博客 | samuel-24276&#39;s Blog
        
    </title>

    <!-- Custom CSS -->
    
<link rel="stylesheet" href="/myblog/css/aircloud.css">

    
<link rel="stylesheet" href="/myblog/css/gitment.css">

    <!--<link rel="stylesheet" href="https://imsun.github.io/gitment/style/default.css">-->
    <link href="//at.alicdn.com/t/font_620856_28hi1hpxx24.css" rel="stylesheet" type="text/css">
    <!-- ga & ba script hoook -->
    <script></script>
<meta name="generator" content="Hexo 7.1.1"></head>

<body>

<div class="site-nav-toggle" id="site-nav-toggle">
    <button>
        <span class="btn-bar"></span>
        <span class="btn-bar"></span>
        <span class="btn-bar"></span>
    </button>
</div>

<div class="index-about">
    <i> Like what you do, do what you like </i>
</div>

<div class="index-container">
    
    <div class="index-left">
        
<div class="nav" id="nav">
    <div class="avatar-name">
        <div class="avatar ">
            <img src="/myblog/img/avatar.jpg" />
        </div>
        <div class="name">
            <i>samuel-24276</i>
        </div>
    </div>
    <div class="contents" id="nav-content">
        <ul>
            <li >
                <a href="/myblog/">
                    <i class="iconfont icon-shouye1"></i>
                    <span>主页</span>
                </a>
            </li>
            <li >
                <a href="/myblog/tags">
                    <i class="iconfont icon-biaoqian1"></i>
                    <span>标签</span>
                </a>
            </li>
            <li >
                <a href="/myblog/archives">
                    <i class="iconfont icon-guidang2"></i>
                    <span>存档</span>
                </a>
            </li>
            <li >
                <a href="/myblog/collect/">
                    <i class="iconfont icon-shoucang1"></i>
                    <span>收藏</span>
                </a>
            </li>
            <li >
                <a href="/myblog/about/">
                    <i class="iconfont icon-guanyu2"></i>
                    <span>关于</span>
                </a>
            </li>
            
            <li>
                <a id="search">
                    <i class="iconfont icon-sousuo1"></i>
                    <span>搜索</span>
                </a>
            </li>
            
        </ul>
    </div>
    
        <div id="toc" class="toc-article">
    <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#1-TCP"><span class="toc-text">1.TCP</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-1-fd-socket-%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6%E4%B8%8ETCP%E7%9A%84%E5%8D%8F%E8%AE%AE%E6%A0%88%E6%9C%89%E4%BB%80%E4%B9%88%E5%85%B3%E7%B3%BB"><span class="toc-text">1.1.fd(socket)文件描述符与TCP的协议栈有什么关系</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-2-tcp%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E9%A1%BA%E5%BA%8F%E4%BC%A0%E8%BE%93%EF%BC%9F"><span class="toc-text">1.2.tcp如何保证顺序传输？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#1-3-%E6%85%A2%E5%90%AF%E5%8A%A8%E4%B8%8E%E6%8B%A5%E5%A1%9E%E6%8E%A7%E5%88%B6"><span class="toc-text">1.3.慢启动与拥塞控制</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#2-UDP"><span class="toc-text">2.UDP</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#2-1-%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF"><span class="toc-text">2.1.应用场景</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-2-%E7%BD%91%E7%BB%9C%E4%BC%A0%E8%BE%93"><span class="toc-text">2.2.网络传输</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#3-socket%E5%A5%97%E6%8E%A5%E5%AD%97"><span class="toc-text">3.socket套接字</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#3-1-server%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B"><span class="toc-text">3.1.server服务端开发流程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-2-client%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B"><span class="toc-text">3.2.client客户端开发流程</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-3-socket%E8%B0%83%E7%94%A8%E5%BA%93%E5%87%BD%E6%95%B0"><span class="toc-text">3.3.socket调用库函数</span></a></li></ol></li></ol>
</div>
    
</div>


<div class="search-field" id="search-field">
    <div class="search-bg" id="search-bg"></div>
    <div class="search-container">
        <div class="search-input">
            <span id="esc-search"> <i class="icon-fanhui iconfont"></i></span>
            <input id="search-input"/>
            <span id="begin-search">搜索</span>
        </div>
        <div class="search-result-container" id="search-result-container">

        </div>
    </div>
</div>

        <div class="index-about-mobile">
            <i> Like what you do, do what you like </i>
        </div>
    </div>
    
    <div class="index-middle">
        <!-- Main Content -->
        


<div class="post-container">
    <div class="post-title">
        TCP/UDP协议与socket编程
    </div>

    <div class="post-meta">
        <span class="attr">发布于：<span>2020-06-05 20:15:38</span></span>
        
        <span class="attr">标签：/
        
        <a class="tag" href="/myblog/tags/#C++" title="C++">C++</a>
        <span>/</span>
        
        <a class="tag" href="/myblog/tags/#网络编程" title="网络编程">网络编程</a>
        <span>/</span>
        
        
        </span>
        <span class="attr">访问：<span id="busuanzi_value_page_pv"></span>
</span>
</span>
    </div>
    <div class="post-content no-indent">
        <h1 id="1-TCP"><a href="#1-TCP" class="headerlink" title="1.TCP"></a>1.TCP</h1><h2 id="1-1-fd-socket-文件描述符与TCP的协议栈有什么关系"><a href="#1-1-fd-socket-文件描述符与TCP的协议栈有什么关系" class="headerlink" title="1.1.fd(socket)文件描述符与TCP的协议栈有什么关系"></a>1.1.fd(socket)文件描述符与TCP的协议栈有什么关系</h2><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">fd = socket = 网络IO</span><br><span class="line"><span class="function"><span class="title">send</span><span class="params">(fd, buffer, length, <span class="number">0</span>)</span></span></span><br><span class="line"><span class="function"><span class="title">recv</span><span class="params">(fd, buffer, length, <span class="number">0</span>)</span></span></span><br></pre></td></tr></table></figure>

<p>TCP的连接和fd的创建都要从三次握手开始，客户端client向服务端server发送请求(请求包括TCP协议头里的标识位syn,序列号seq&#x3D;12345)，服务端处于listen状态，第一次握手完成。然后服务端回应客户端，发送确认信号ack、acknum&#x3D;12346(acknum是在seq基础上加1)、syn、seq&#x3D;3214，第二次握手完成，第二次握手表示以前的信息全部确认。之后客户端回应服务端，ack, acknum&#x3D;3215(acknum是上一轮握手的seq值加1)，第三次握手完成。<br>第一次握手客户端发送syn信号时，服务端会形成一个用于确认数据完整性的tcb节点，也就是TCP的控制块，它包含了TCP的11个状态，tcb在TCP连接的整个生命周期内都会存在。因为客户端一般有多个，所以服务端会形成一个syn队列存储tcb节点。<br>同理第三次握手时，服务端也会生成一个accept队列存储tcb节点。服务端的accept队列会去syn队列查找一个刚到的tcb节点，并将它移动到accept队列。当accept队列里有节点时就会调用accept()函数，该函数会取出三次握手完成后的tcb节点，为这个节点分配fd,并分配id:<code>clientId = accept();</code>。那么第三次握手时accept队列是如何从syn队列里找到刚才的tcb节点呢？<br>通过五元组查询(fd–&gt;(sip, dip, sport, dport, proto))，这个tcb节点是一个五元组，内容为(sip, dip, sport, dport, proto),即（原Ip，目的IP，原端口，目的端口，协议）。</p>
<ul>
<li>1.调用send()函数时，我们是把用户buffer里的数据放到tcb.sendbuffer里面，buffer–&gt;tcb.sendbuffer；</li>
<li>2.调用recv()函数时，正好相反，是把tcb.recvbuffer里的数据复制到用户buffer里面,tcb.recvbuffer–&gt;buffer。<br>所谓的零拷贝是把用户态数据放到用户态数据里面，并不是不拷贝，中间是有拷贝的。</li>
</ul>
<p>tcp如何学习？</p>
<ul>
<li>1.找一本权威的书，如TCP&#x2F;IP详解1，2，3卷</li>
<li>2.对比TCP源码，linux&#x2F;tcp.c Ntytcp lwip</li>
<li>3.多跟人沟通</li>
<li>4.产出结果：自己实现一个</li>
</ul>
<h2 id="1-2-tcp如何保证顺序传输？"><a href="#1-2-tcp如何保证顺序传输？" class="headerlink" title="1.2.tcp如何保证顺序传输？"></a>1.2.tcp如何保证顺序传输？</h2><p>tcp中先发后到和后发先到是无法保证的，所以要对包进行编号，假设有1<del>10号包，客户端向服务端发送这10个包，服务器接收了1，2，5，10共计4个包，为了确定接受数据完整性，服务端会向客户端发送一个延迟ack用于确认，ack&#x3D;3，也就是3号包之前的数据全部收到。这是需要再次发送3</del>10号包，5号包和10号包需要重传。<br>UDP相对TCP是可靠传输，可以借助一些应用层协议(KCP、UDT)可靠，适用于游戏，保证实时性。UDP通过牺牲效率弥补实时性，依次发送1~10号包，客户端接收到服务端发回的ack信号，再继续发送下一个包，一次一确认。  </p>
<blockquote>
<p>业界大牛：KCP创始人林伟，知乎用户韦易笑，GitHub用户skywind3000。</p>
</blockquote>
<h2 id="1-3-慢启动与拥塞控制"><a href="#1-3-慢启动与拥塞控制" class="headerlink" title="1.3.慢启动与拥塞控制"></a>1.3.慢启动与拥塞控制</h2><p>TCP能根据网络传输状况，判断应该往网路上丢多少包。比如从济南往北京送货，一共有1万车货物，需要一次性往道路上发多少车货物我们是不确定的，要根据道路情况来决定我们此时发多少车货物。<br>所谓<strong>慢启动</strong>，就是从济南往北京发货，先发一车货物（如何知道货物是否送达以及花费时间？通过TCP的三次握手来确定客户端到服务端的通信时间RTT。RTT是一个动态的值，根据网络的回传时间确定，抖动很大。RTT3 &#x3D; 0.9*RTT0 + 0.1RTT1，也就是当前RTT依赖前两次的RTT），若一车货物能够送达，下次就发两车，下一次传送的数据是上一次的两倍；如果加倍后的的货物没有送达，那就送没有送达的一半货物加上两者之差的一半（32车没送达，那下次送16+8车货物），若这次送达，则再加上两者之差的一半（即24+（32-24）&#x2F;2&#x3D;28车），直到最后达到一个稳态。<br>拥塞控制，</p>
<h1 id="2-UDP"><a href="#2-UDP" class="headerlink" title="2.UDP"></a>2.UDP</h1><h2 id="2-1-应用场景"><a href="#2-1-应用场景" class="headerlink" title="2.1.应用场景"></a>2.1.应用场景</h2><ul>
<li>1.音视频通话、直播</li>
<li>2.即时战略游戏</li>
<li>3.股票行情</li>
<li>4.物联网</li>
<li>5.http3 quic(quick udp Internet connection)快速udp连接</li>
</ul>
<h2 id="2-2-网络传输"><a href="#2-2-网络传输" class="headerlink" title="2.2.网络传输"></a>2.2.网络传输</h2><p>数据包在网络上的传输是乱序的，网络传输过程中丢包原因如下：</p>
<ul>
<li>1.网路阻塞</li>
<li>2.路由器性能不足</li>
<li>3.信号问题，比如WIFI在卧室，我们到客厅会发现信号变差</li>
</ul>
<p>TCP在网络丢包时会选择重传，一次重传时，花费2RTO（<strong>超时重传时间</strong>）,那么二次重传时花费时间为4RTO,三次重传时花费时间为8RTO。<br>TCP传输数据时解决包乱序的方法是发送包时给包加序号，通过send(fd, buffer, length)可以返回发送包的大小，用ret存储起来。而UDP通过sendto()发送数据时有MTU（最大传输单元）的限制，传输数据超过MTU会报错。UDP被封装到IP报文里面，报文的header最小为20字节，若IP报文1500字节，则UDP数据（MTU）&#x3D;1500-20-8&#x3D;1472字节，8字节是UDP头。</p>
<h1 id="3-socket套接字"><a href="#3-socket套接字" class="headerlink" title="3.socket套接字"></a>3.socket套接字</h1><p>socket是在应用层和传输层之间的一个<strong>抽象层</strong>，它把TCP&#x2F;IP复杂的操作抽象为几个简单的接口供应用层调用，去实现进程在网络中的通信。</p>
<p>TCP面向连接，可靠传输（需要认证和回传），传输速度慢；而UDP无连接，传输不可靠，传输速度慢。</p>
<h2 id="3-1-server服务端开发流程"><a href="#3-1-server服务端开发流程" class="headerlink" title="3.1.server服务端开发流程"></a>3.1.server服务端开发流程</h2><ul>
<li>1.socket()服务器创建socket</li>
<li>2.bingder()绑定服务器IP（socket）和端口号，通过IP确定哪一台主机，通过端口号确定哪一个进程。</li>
<li>3.listen()监听端口号，判断有无来自客户端的请求</li>
<li>4.若有请求，则accept()接受来自客户端的连续请求，并建立连接</li>
<li>5.连接成功后，收——recv()从socket中读取字符</li>
<li>6.close()关闭socket</li>
</ul>
<h2 id="3-2-client客户端开发流程"><a href="#3-2-client客户端开发流程" class="headerlink" title="3.2.client客户端开发流程"></a>3.2.client客户端开发流程</h2><ul>
<li>1.socket()创建socket</li>
<li>2.connect()连接指定的计算机端口，参数指明服务器IP和端口号</li>
<li>3.连接成功后，发——send()向socket写入信息</li>
<li>4.close()关闭socket</li>
</ul>
<h2 id="3-3-socket调用库函数"><a href="#3-3-socket调用库函数" class="headerlink" title="3.3.socket调用库函数"></a>3.3.socket调用库函数</h2><ul>
<li>1.创建套接字socket(af, type, protocol)</li>
<li>2.建立地址和套接字的联系bind(sockid, localaddr, addrlen)</li>
<li>3.服务器监听客户端请求listen(sockid, quenlen)</li>
<li>4.建立服务器，客户端连接（面向连接TCP）<br>  客户端连接请求connect(sockid, destaddr, addrlen)<br>  服务器等待从编号为sockid的socket上接受客户端请求newsockid &#x3D; accept(sockid, clientaddr, addrlen)</li>
<li>5.发送&#x2F;接收数据，面向连接<br>  send(sockid, buffer, bufflen)<br>  recv(sockid, buffer, bufflen, flags)</li>
<li>6.释放套接字closesocket(sockid)<br>accept()和recv()是阻塞函数，操作响应之前一直会停顿在这里直到操作完成才会进行下一步操作，非阻塞函数被调用之后就会立刻执行下一个函数。</li>
</ul>
<hr>

        
            <div class="donate-container">
    <div class="donate-button">
        <button id="donate-button">赞赏</button>
    </div>
    <div class="donate-img-container hide" id="donate-img-container">
        <img id="donate-img" src="" data-src="/myblog/img/donate.jpg">
        <p> 感谢鼓励 </p>
    </div>
</div>
        
        <br />
        <div id="comment-container">
        </div>
        <div id="disqus_thread"></div>
        <div id="lv-container"></div>
        <div class="giscus"></div>
    </div>
</div>

    </div>
</div>


<footer class="footer">
    <ul class="list-inline text-center">
        
        

        

        

        
        <li>
            <a target="_blank"  href="https://github.com/samuel-24276">
                            <span class="fa-stack fa-lg">
                                <i class="iconfont icon-github"></i>
                            </span>
            </a>
        </li>
        

        

    </ul>
    
    <p>
        <span>/</span>
        
        <span><a target="_blank" rel="noopener" href="https://github.com/samuel-24276">samuel-24276&#39;s Page</a></span>
        <span>/</span>
        
        <span><a target="_blank" rel="noopener" href="https://beian.miit.gov.cn/">北京-未备案</a></span>
        <span>/</span>
        
        <span><a href="#">返回顶部</a></span>
        <span>/</span>
        
    </p>
    
    <p>
        <span id="busuanzi_container_site_pv">
            <span id="busuanzi_value_site_pv"></span>PV
        </span>
        <span id="busuanzi_container_site_uv">
            <span id="busuanzi_value_site_uv"></span>UV
        </span>
        Created By <a target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>  Theme <a target="_blank" rel="noopener" href="https://github.com/aircloud/hexo-theme-aircloud">AirCloud</a></p>
</footer>




</body>

<script>
    // We expose some of the variables needed by the front end
    window.hexo_search_path = "search.json"
    window.hexo_root = "/myblog/"
    window.isPost = true
</script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>

<script src="/myblog/js/index.js"></script>

<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>






    <script type="text/javascript">
       (function() {
           if (typeof LivereTower === 'function') { return; }

           var j, d = document.getElementById('lv-container');

           d.setAttribute('data-id','city');
           d.setAttribute('data-uid' , 'MTAyMC80OTA5OC8yNTU5Mw==');

           j = document.createElement('script');
           j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
           j.async = true;

           d.appendChild(j);
       })();
    </script>
    <noscript>为正常使用来必力评论功能请激活JavaScript</noscript>
    </div>

</html>
